package com.zyf.project.binaryproto.contract;

import com.zyf.project.binaryproto.specification.DataSpecification;
import utils.binary.io.BytesInputStream;
import utils.binary.io.BytesOutputBuffer;

import java.io.ByteArrayOutputStream;
import java.io.OutputStream;
import java.util.function.Function;

/**
 * <h1>数据契约的二进制编码器</h1>
 *
 * @author Zhou Yifan
 */
public interface DataContractEncoder {

    /**
     * 获取数据契约的格式标准
     *
     * @return {@link DataSpecification}
     */
    DataSpecification getSpecification();

    /**
     * 获取数据契约的接口类型
     *
     * @return Class
     */
    Class<?> getContractType();

    /**
     * 将数据格式标准序列化，送到指定的 BytesOutputBuffer 中
     *
     * @param dataContract 数据
     * @param buffer       {@link BytesOutputBuffer}
     * @return 写入的字节数
     */
    int encode(Object dataContract, BytesOutputBuffer buffer);

    /**
     * 将数据格式标准序列化，送到指定的 OutputStream
     *
     * @param data         数据
     * @param outputStream {@link OutputStream}
     */
    default void encode(Object data, OutputStream outputStream) {
        BytesOutputBuffer buffer = new BytesOutputBuffer();
        encode(data, buffer);
        buffer.writeTo(outputStream);
    }

    /**
     * 将数据格式标准序列化
     *
     * @param data 数据
     * @return 标准序列化后的字节数组
     */
    default byte[] encode(Object data) {
        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        encode(data, byteArrayOutputStream);
        return byteArrayOutputStream.toByteArray();
    }

    /**
     * 按照数据格式标准将指定的二进制输入流反序列化生成数据对象；
     *
     * @param bytesStream {@link BytesInputStream}
     * @return 反序列化后对应的数据类型
     */
    <T> T decode(BytesInputStream bytesStream);

    /**
     * 按照数据格式标准将指定的二进制输入流反序列化生成数据对象
     *
     * @param bytes 指定的二进制数组
     * @param <T>   对应的数据类型
     * @return 反序列化后对应的数据类型
     */
    default <T> T decode(byte[] bytes) {
        return decode(new BytesInputStream(bytes, 0, bytes.length));
    }

    /**
     * 按照数据格式标准将指定的二进制输入流反序列化生成数据对象
     *
     * @param bytes  指定的二进制数组
     * @param offset 指定位置
     * @param length 长度
     * @param <T>    对应的数据类型
     * @return 反序列化后对应的数据类型
     */
    default <T> T decode(byte[] bytes, int offset, int length) {
        return decode(new BytesInputStream(bytes, offset, length));
    }

    /**
     * 数组创建函数，用于decode
     *
     * @return {@link Function}
     */
    Function<Integer, ?> getArrayConstructor();
}
